package io.noties.markwon.plugin.inline

import org.commonmark.internal.InlineParserImpl
import org.commonmark.internal.inline.*
import org.commonmark.parser.InlineParser
import org.commonmark.parser.InlineParserContext
import org.commonmark.parser.InlineParserFactory
import org.commonmark.parser.delimiter.DelimiterProcessor
import java.util.*
import kotlin.collections.ArrayList


/**
 * @see .factoryBuilder
 * @see .factoryBuilderNoDefaults
 * @see FactoryBuilder
 *
 * @since 4.2.0
 */
class MarkwonInlineParser(inlineParserContext:InlineParserContext,
                          val referencesEnabled:Boolean,
                          val inlineProcessors:List<InlineContentParser>,
                          val delimiterProcessors:List<DelimiterProcessor>): InlineParserImpl(inlineParserContext) {

}



interface FactoryBuilder {
    /**
     * @see InlineProcessor
     */
    fun addInlineProcessor(processor: InlineContentParser): FactoryBuilder

    /**
     * @see AsteriskDelimiterProcessor
     *
     * @see UnderscoreDelimiterProcessor
     */
    fun addDelimiterProcessor(processor: DelimiterProcessor): FactoryBuilder

    /**
     * Indicate if markdown references are enabled. By default = `true`
     */
    fun referencesEnabled(referencesEnabled: Boolean): FactoryBuilder
    fun excludeInlineProcessor(processor: Class<out InlineContentParser?>): FactoryBuilder
    fun excludeDelimiterProcessor(processor: Class<out DelimiterProcessor?>): FactoryBuilder
    fun build(): InlineParserFactory
}

interface FactoryBuilderNoDefaults : FactoryBuilder {
    /**
     * Includes all default delimiter and inline processors, and sets `referencesEnabled=true`.
     * Useful with subsequent calls to [.excludeInlineProcessor] or [.excludeDelimiterProcessor]
     */
    fun includeDefaults(): FactoryBuilder
}

class FactoryBuilderImpl : FactoryBuilderNoDefaults {
    private val inlineProcessors: MutableList<InlineContentParser> = ArrayList(3)
    private val delimiterProcessors: MutableList<DelimiterProcessor> = ArrayList(3)
    private var referencesEnabled = false
    override fun addInlineProcessor(processor: InlineContentParser): FactoryBuilder {
        inlineProcessors.add(processor)
        return this
    }

    override fun addDelimiterProcessor(processor: DelimiterProcessor): FactoryBuilder {
        delimiterProcessors.add(processor)
        return this
    }

    override fun referencesEnabled(referencesEnabled: Boolean): FactoryBuilder {
        this.referencesEnabled = referencesEnabled
        return this
    }

    override fun includeDefaults(): FactoryBuilder {

        // by default enabled
        referencesEnabled = true
        inlineProcessors.addAll(
            listOf(
                AutolinkInlineParser(),
                BackslashInlineParser(),
                BackticksInlineParser(),
                //BangInlineProcessor(),
                //CloseBracketInlineProcessor(),
                EntityInlineParser(),
                HtmlInlineParser()
                //NewLineInlineProcessor(),
                //OpenBracketInlineProcessor()
            )
        )
        delimiterProcessors.addAll(
            listOf(
                AsteriskDelimiterProcessor(),
                UnderscoreDelimiterProcessor()
            )
        )
        return this
    }

    override fun excludeInlineProcessor(type: Class<out InlineContentParser>): FactoryBuilder {
        var i = 0
        val size = inlineProcessors.size
        while (i < size) {
            if (type == inlineProcessors[i].javaClass) {
                inlineProcessors.removeAt(i)
                break
            }
            i++
        }
        return this
    }

    override fun excludeDelimiterProcessor(type: Class<out DelimiterProcessor>): FactoryBuilder {
        var i = 0
        val size = delimiterProcessors.size
        while (i < size) {
            if (type == delimiterProcessors[i].javaClass) {
                delimiterProcessors.removeAt(i)
                break
            }
            i++
        }
        return this
    }

    override fun build(): InlineParserFactory {
        return InlineParserFactoryImpl(referencesEnabled, inlineProcessors, delimiterProcessors)
    }

    companion object {
        /**
         * Creates an instance of [FactoryBuilder] and includes all defaults.
         *
         * @see .factoryBuilderNoDefaults
         */
        fun factoryBuilder(): FactoryBuilder {
            return FactoryBuilderImpl().includeDefaults()
        }

        /**
         * NB, this return an *empty* builder, so if no [FactoryBuilderNoDefaults.includeDefaults]
         * is called, it means effectively **no inline parsing** (unless further calls
         * to [FactoryBuilder.addInlineProcessor] or [FactoryBuilder.addDelimiterProcessor]).
         */
        fun factoryBuilderNoDefaults(): FactoryBuilderNoDefaults {
            return FactoryBuilderImpl()
        }

}
}

 class InlineParserFactoryImpl(
    private val referencesEnabled: Boolean,
    private val inlineProcessors: List<InlineContentParser>,
    private val delimiterProcessors: MutableList<DelimiterProcessor>
) : InlineParserFactory {
    override fun create(inlineParserContext: InlineParserContext): InlineParser {
        val delimiterProcessors: MutableList<DelimiterProcessor>
        val customDelimiterProcessors = inlineParserContext.customDelimiterProcessors
        val size = customDelimiterProcessors?.size ?: 0
        if (size > 0) {
            delimiterProcessors = ArrayList(size + this.delimiterProcessors.size)
            delimiterProcessors.addAll(this.delimiterProcessors)
            delimiterProcessors.addAll(customDelimiterProcessors!!)
        } else {
            delimiterProcessors = this.delimiterProcessors
        }
        return MarkwonInlineParser(inlineParserContext,referencesEnabled,inlineProcessors,delimiterProcessors)
    }
}